﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using HtmlAgilityPack;
using System.Web;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private Dictionary<string, string> cssDictionary;

        const string xpathStr = "//a[contains(@href,'/wiki/')]";//获取右侧导航a标签(只包含路径/wiki/)
        const string wikiDefaultPage = "1首页wiki.html";
        private const string jinduFormat = "进度 {0}/{1}";

        //https://www.cnblogs.com/mingjiatang/p/5079632.html winform ui异步
        private delegate void UpdateUIDelegate(int num, int jdCount);

        public delegate void AccomplishTask(string pathDiv, List<PageInfo> pageInfoList,int stepCount);//声明一个在完成任务时通知主线程的委托
        public AccomplishTask TaskCallBack;

        private void UpdateUI(int step, int stepCount)
        {
            if (this.InvokeRequired)//跨线程访问
            {
                UpdateUIDelegate updateCallback = new UpdateUIDelegate(UpdateUI);
                this.Invoke(updateCallback,new object[]{ step , stepCount });
            }
            else
            {
                this.progressBar1.Value += step;
                this.lb_jd.Text = string.Format(jinduFormat, this.progressBar1.Value, stepCount);
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //ReplaceGithubUrl(); MessageBox.Show("更新git url完毕"); return; //测试代码

            if (txb_url.Text.Trim().Length == 0)
            {
                MessageBox.Show("请填写Github wiki地址");
                return;
            }
            else if (!txb_url.Text.ContainsByIgnoreCase("https://github.com") || !txb_url.Text.ContainsByIgnoreCase("/wiki"))
            {
                MessageBox.Show("Github wiki地址不正确。url必须含有wiki");
                return;
            }

            cssDictionary = new Dictionary<string, string>();

            try
            {
                var homeHtml = DownLoadFileBllcs.HttpGET(txb_url.Text);

                HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
                doc.LoadHtml(homeHtml);

                HtmlNodeCollection pageNode = doc.DocumentNode.SelectNodes(xpathStr);
                List<PageInfo> pageInfoList = new List<PageInfo>();
                string gitName = StringHelper.GetBetweenStr(txb_url.Text, "github.com/", "/wiki").Split('/')[1];
                string pathDiv = txb_path.Text + "\\" + gitName;

                int stepCount = 0;//进度值
                if (pageNode != null)
                {
                    TaskCallBack += Accomplish;//绑定完成任务要调用的委托

                    stepCount = pageNode.Count + 1;//还有一步是更新下载的文件
                    this.progressBar1.Maximum = stepCount;
                    this.progressBar1.Value = 0;

                    Thread thread = new Thread(new ThreadStart(() => DownLoadWiki(pageNode, pageInfoList, pathDiv, stepCount))) { IsBackground = true };
                    thread.Start();
                }
                else
                {
                    MessageBox.Show("没有下载Wiki");
                }

                //UpdateUI(1, stepCount);
            }
            catch (Exception exception)
            {
                MessageBox.Show("异常:" + exception.Message + System.Environment.NewLine + exception.StackTrace);
            }
        }

        private void DownLoadWiki(HtmlNodeCollection pageNode, List<PageInfo> pageInfoList, string pathDiv,int stepCount)
        {
            PageInfo tempPage;
            string requestUrl;
            string html;
            string href;
            for (var index = 0; index < pageNode.Count; index++)
            {
                var pn = pageNode[index];
                href = pn.Attributes["href"]?.Value;
                if (!string.IsNullOrEmpty(href))
                {
                    tempPage = new PageInfo();
                    tempPage.url = href;
                    requestUrl =
                        "https://github.com" +
                        href.Replace("https://github.com", string.Empty); //补全 github.com开头
                    tempPage.link = GetLinkByUrl(href);
                    tempPage.Text = pn.InnerText;
                    if (tempPage.link.Length > 0 && !tempPage.link.Contains("/") &&
                        pageInfoList.All(p => p.link != tempPage.link))
                    {
                        pageInfoList.Add(tempPage);
                        html = DownLoadFileBllcs.HttpGET(requestUrl);
                        DownLoadFileBllcs.SyncHtmlByUrl(html, pathDiv,
                            HttpUtility.UrlDecode(tempPage.link) + ".html");
                    }
                }

                UpdateUI(1,stepCount);
            }

            //任务完成时通知主线程作出相应的处理
            TaskCallBack(pathDiv,pageInfoList,stepCount);
        }

        //完成任务时需要调用
        private void Accomplish(string pathDiv, List<PageInfo> pageInfoList,int stepCount)
        {
            //还可以进行其他的一些完任务完成之后的逻辑处理
            //首页位置 读取下载
            string html = DownLoadFileBllcs.HttpGET(txb_url.Text.Trim());
            DownLoadFileBllcs.SyncHtmlByUrl(html, pathDiv, wikiDefaultPage);

            if (pageInfoList.Count > 0)
            {
                //MessageBox.Show("只下载成功！待完善a标签");return;//测试代码

                ReplaceGithubUrl();

                //添加 大屏字体调优css.7z
                string zip = "\\大屏字体调优css.7z";
                string css7z = System.AppDomain.CurrentDomain.BaseDirectory + zip;
                if (File.Exists(css7z)) //必须判断要复制的文件是否存在
                {
                    File.Copy(css7z, pathDiv + "\\css" + zip, true); //三个参数分别是源文件路径，存储路径，若存储路径有相同文件是否替换
                }

                //压缩
                // string zipPath = pathDiv + ".zip";
                // bool boolResult = ZipHelper.ZipDirectory(pathDiv, zipPath);

                //删除文件
                //DownLoadFileBllcs.DeleteDir(pathDiv);

                //下载
                // if (boolResult)//压缩成功并下载
                // {
                //     MessageBox.Show("压缩成功！");
                // }
                // else
                // {
                //     MessageBox.Show("压缩失败！");
                // }
            }

            UpdateUI(1, stepCount);
            MessageBox.Show("下载成功！");
        }


        /// <summary>
        /// 获取短链接
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        private string GetLinkByUrl(string url)
        {
            if (url.Contains("#"))
            {   //github.com/wiki/abc#id
                return StringHelper.GetBetweenStr(url, "/wiki/", "#");
            }

            if (url.Contains("?"))
            {   //github.com/wiki/abc?id
                return StringHelper.GetBetweenStr(url, "/wiki/", "?");
            }

            int indexNum = url.IndexOf("/wiki/") + "/wiki/".Length;
            return url.Substring(indexNum);
        }

        /// <summary>
        /// 替换github链接标签
        /// </summary>
        private void ReplaceLinkStr(string filePath)
        {
            string html = TxtHelper.ReadTxt(filePath);
            if (string.IsNullOrEmpty(html)) return;

            StringBuilder sbHtml = new StringBuilder(html);

            HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
            doc.LoadHtml(html);
            HtmlNodeCollection pageNode = doc.DocumentNode.SelectNodes("//a[@href]");

            /*
              链接 7种样式 :https://github.com/dotnetcore/FreeSql/wiki/%E9%AA%9A%E6%93%8D%E4%BD%9C
                            https://github.com/2881099/FreeSql/wiki/%e6%b7%bb%e5%8a%a0#2%E6%89%B9%E9%87%8F%E6%8F%92%E5%85%A5
                            /dotnetcore/FreeSql/wiki/%E9%AA%9A%E6%93%8D%E4%BD%9C
                            如果项目名称也是wiki(暂不支持)         /dotnetcore/wiki/wiki/%E9%AA%9A%E6%93%8D%E4%BD%9C 
                            /dotnetcore/FreeSql/wiki  首页

                            aop  短链接
                            #aop 短链接
                            
             */

            if (pageNode != null && pageNode.Count > 0)
            {
                string href;
                string str1;//被替换后的字符串
                string lastUrl;// /后面最后的url(/dotnetcore/FreeSql/wiki/aop 为aop )
                foreach (var pn in pageNode)
                {
                    href = pn.Attributes["href"].Value;

                    if (href.IndexOf('.') == 0 || href == wikiDefaultPage) continue;

                    if (href.Contains("wiki"))//带wiki
                    {
                        lastUrl = href.Split('/').Last();
                        if (lastUrl.ToLower() == "wiki") //  /dotnetcore/FreeSql/wiki  首页
                        {
                            sbHtml.Replace("\"" + href + "\"", "'" + wikiDefaultPage + "'");
                            sbHtml.Replace("'" + href + "'", "'" + wikiDefaultPage + "'");
                        }
                        else
                        {
                            str1 = href.Substring(href.IndexOf("/wiki/") + "/wiki/".Length);

                            if (str1.Contains("?"))//同时有?和# 情况
                            {
                                string[] tempStrs = str1.Split('?');
                                str1 = tempStrs[0] + ".html?" + tempStrs[1];
                            }
                            else
                            {
                                if (str1.Contains("#"))
                                {
                                    string[] tempStrs = str1.Split('#');
                                    str1 = tempStrs[0] + ".html#" + tempStrs[1];
                                }
                                else
                                {
                                    str1 = str1 + ".html";
                                }
                            }
                            
                            sbHtml.Replace(href, str1);
                        }
                    }
                    else if (!href.Contains("/") && !href.Contains("."))//短链接
                    {
                        if (href.Contains("?"))//同时有?和# 情况
                        {
                            sbHtml.Replace("\"" + href + "\"", "'" + href.Replace("?", ".html?") + "'");
                            sbHtml.Replace("'" + href + "'", "'" + href.Replace("?", ".html?") + "'");
                        }
                        else
                        {
                            if (href.Contains("#"))
                            {
                                sbHtml.Replace("\"" + href + "\"", "'" + href.Replace("#", ".html#") + "'");
                                sbHtml.Replace("'" + href + "'", "'" + href.Replace("#", ".html#") + "'");
                            }
                            else
                            {
                                sbHtml.Replace("\"" + href + "\"", "'" + href + ".html'");
                                sbHtml.Replace("'" + href + "'", "'" + href + ".html'");
                            }
                        }
                    }
                }
            }

            //删除github的css 文件,添加本地css
            StringBuilder newHtml = new StringBuilder(sbHtml.ToString());
            HtmlAgilityPack.HtmlDocument doc2 = new HtmlAgilityPack.HtmlDocument();
            doc2.LoadHtml(sbHtml.ToString());
            var cssNode = doc2.DocumentNode.SelectNodes("//link[contains(@href,'css')]");//获取所有的css引用
            if (cssNode != null)
            {
                foreach (var pn in cssNode)
                {
                    newHtml.Replace(pn.OuterHtml.Replace(">", " />"), GetCSSCode(pn));
                }
            }

            TxtHelper.WriteTxt(filePath, newHtml.ToString());
        }

        private string GetCSSCode(HtmlNode hn)
        {
            var key = hn.Attributes["href"].Value;
            if (!cssDictionary.ContainsKey(key))
            {
                string gitName = StringHelper.GetBetweenStr(txb_url.Text, "github.com/", "/wiki").Split('/')[1];
                cssDictionary[key] = (cssDictionary.Count + 1).ToString();
                DownLoadFileBllcs.FileDownLoad(key, txb_path.Text + "\\" + gitName + "\\css\\" + cssDictionary[key] + ".css");
            }
            return "<link href='css/" + cssDictionary[key] + ".css' rel='stylesheet' type='text/css'/>";
        }

        /// <summary>
        /// 批量替换github url成本地标签。删除外部css引用
        /// </summary>
        private void ReplaceGithubUrl()
        {
            //读取页面
            DirectoryInfo adminDir = new DirectoryInfo(txb_path.Text);
            var dirList = adminDir.GetDirectories().OrderBy(p => p.Name);
            IEnumerable<FileInfo> htmlList;
            foreach (var dir in dirList)
            {
                htmlList = dir.EnumerateFiles("*.html").OrderBy(p => p.Name);
                foreach (var html in htmlList)
                {
                    //ddl.Items.Add(dir.Name + "/" + html.Name, dir.Name + "/" + html.Name);
                    ReplaceLinkStr(txb_path.Text + "\\" + dir.Name + "\\" + html.Name);
                }
            }
        }

        private void button3_Click(object sender, EventArgs e)
        {
            MD2Html htmlForm = new MD2Html();
            this.Hide();
            htmlForm.ShowDialog();
            this.Show();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            DownImagesForm htmlForm = new DownImagesForm();
            this.Hide();
            htmlForm.ShowDialog();
            this.Show();
        }
    }


    /// <summary>
    /// 目录列表
    /// </summary>
    public class PageInfo
    {
        /// <summary>
        /// url:  /dotnetcore/FreeSql/wiki/%E9%AA%9A%E6%93%8D%E4%BD%9C 等
        /// </summary>
        public string url { get; set; }

        /// <summary>
        /// 短链接 : %E9%AA%9A%E6%93%8D%E4%BD%9C
        /// </summary>
        public string link { get; set; }

        /// <summary>
        /// 显示文本 : 安装
        /// </summary>
        public string Text { get; set; }
    }
}
/*todo
             wiki 有效地址判断(只下载wiki链接)
             链接重复的问题
             链接中文转实体的问题，也会导致重复的问题
             链接替换为本地链接的问题(根据a标签原html替换？)
             批量请求地址
             样式的问题(2个css文件)

            Xpath表达式提示文章显示

            //a[contains(@href,'https://github.com/2881099/FreeSql/wiki')]
             */
